package poker.plans.player.betting;

import jadex.runtime.*;

import poker.beliefs.Bet;
import poker.beliefs.DoBet;
import poker.beliefs.Hand;
import poker.beliefs.Money;
import poker.util.HandChecker;

public class ConservativeBettingPlan extends Plan {

	private static final int LIMIT_HIGHEST_VALUE = 10;

	private static final int BET_INCREMENT = 5;

	public void body() {

		System.out.println("PLAYER " + getAgentName()
				+ ": Conservative betting");

		IMessageEvent request = (IMessageEvent) getInitialEvent();

		//We get the amount of money already used by player-->OLD MAXBET
		Integer aux = (Integer) getBeliefbase().getBelief("mypot").getFact();
		Money budget = (Money) getBeliefbase().getBelief("money").getFact();
		int mypot = 0;
		if (aux != null) {
			mypot = aux.intValue();
		}
		//And the current bet
		int currentBet = ((Integer) request.getContent()).intValue();

		Bet bet = null;
		Hand myHand = (Hand) getBeliefbase().getBelief("hand").getFact();
		switch (myHand.getCardCount()) {
		case 2: // Pre-Flop
			bet = preFlopBet(myHand, currentBet, mypot);
			break;
		case 5: // Flop
			bet = flopBet(myHand, currentBet, mypot);
			break;
		case 6: // Turn
			bet = turnBet(myHand, currentBet, mypot);
			break;
		case 7: // River
			bet = riverBet(myHand, currentBet, mypot);
			break;
		}
		
		if (currentBet > budget.getMoney()) {
			bet = new Bet(0, Bet.FOLD);
		}

		System.out.println("PLAYER " + getAgentName() + " Bet : " + bet);

		// Reply to the croupier with the bet
		IMessageEvent msg = request.createReply("do_bet");
		msg.setContent(new DoBet(bet));
		sendMessage(msg);
	}

	// Private methods to decide the bet in each round
	private Bet preFlopBet(Hand h, int money, int pot) {
		Bet bet;
		Integer blind = (Integer) getBeliefbase().getBelief("blind").getFact();
		if (HandChecker.checkOnePair(h))
			bet = new Bet(money + HandChecker.ONE_PAIR * BET_INCREMENT,
					Bet.RAISE);
		else if (h.getHighestValue() >= LIMIT_HIGHEST_VALUE)
			bet = new Bet(money, Bet.CALL);
		else
			bet = new Bet(money, Bet.FOLD);

		if (blind!= null & bet.getResponse()==Bet.FOLD){
			bet = new Bet(money, Bet.CALL);
		}
		return bet;
	}

	private Bet flopBet(Hand h, int money, int pot) {
		Bet bet = null;
		switch (HandChecker.rankHand(h)) {
		case HandChecker.HIGH_CARD:
			bet = new Bet(money, Bet.FOLD);
			break;
		case HandChecker.ONE_PAIR:
			bet = new Bet(money, Bet.CALL);
			break;
		case HandChecker.TWO_PAIRS:
			bet = new Bet(money, Bet.CALL);
			break;
		case HandChecker.THREE_OF_A_KIND:
			bet = new Bet(money + HandChecker.THREE_OF_A_KIND * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.STRAIGHT:
			bet = new Bet(money + HandChecker.STRAIGHT * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.FLUSH:
			bet = new Bet(money + HandChecker.FLUSH * BET_INCREMENT, Bet.RAISE);
			break;
		case HandChecker.FULL_HOUSE:
			bet = new Bet(money + HandChecker.FULL_HOUSE * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.FOUR_OF_A_KIND:
			bet = new Bet(money + HandChecker.FOUR_OF_A_KIND * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.STRAIGHT_FLUSH:
			bet = new Bet(money + HandChecker.STRAIGHT_FLUSH * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.ROYAL_FLUSH:
			bet = new Bet(money + HandChecker.ROYAL_FLUSH * BET_INCREMENT,
					Bet.RAISE);
			break;
		}
		return bet;
	}

	private Bet turnBet(Hand h, int money, int pot) {
		Bet bet = null;
		switch (HandChecker.rankHand(h)) {
		case HandChecker.ONE_PAIR:
			bet = new Bet(money, Bet.FOLD);
			break;
		case HandChecker.TWO_PAIRS:
			bet = new Bet(money, Bet.CALL);
			break;
		case HandChecker.THREE_OF_A_KIND:
			bet = new Bet(money, Bet.CALL);
			break;
		case HandChecker.STRAIGHT:
			bet = new Bet(money + HandChecker.STRAIGHT * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.FLUSH:
			bet = new Bet(money + HandChecker.FLUSH * BET_INCREMENT, Bet.RAISE);
			break;
		case HandChecker.FULL_HOUSE:
			bet = new Bet(money + HandChecker.FULL_HOUSE * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.FOUR_OF_A_KIND:
			bet = new Bet(money + HandChecker.FOUR_OF_A_KIND * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.STRAIGHT_FLUSH:
			bet = new Bet(money + HandChecker.STRAIGHT_FLUSH * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.ROYAL_FLUSH:
			bet = new Bet(money + HandChecker.ROYAL_FLUSH * BET_INCREMENT,
					Bet.RAISE);
			break;
		}
		return bet;
	}

	private Bet riverBet(Hand h, int money, int pot) {
		Bet bet = null;
		switch (HandChecker.rankHand(h)) {
		case HandChecker.TWO_PAIRS:
			bet = new Bet(money, Bet.CALL);
			break;
		case HandChecker.THREE_OF_A_KIND:
			bet = new Bet(money, Bet.CALL);
			break;
		case HandChecker.STRAIGHT:
			bet = new Bet(money + HandChecker.STRAIGHT * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.FLUSH:
			bet = new Bet(money + HandChecker.FLUSH * BET_INCREMENT, Bet.RAISE);
			break;
		case HandChecker.FULL_HOUSE:
			bet = new Bet(money + HandChecker.FULL_HOUSE * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.FOUR_OF_A_KIND:
			bet = new Bet(money + HandChecker.FOUR_OF_A_KIND * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.STRAIGHT_FLUSH:
			bet = new Bet(money + HandChecker.STRAIGHT_FLUSH * BET_INCREMENT,
					Bet.RAISE);
			break;
		case HandChecker.ROYAL_FLUSH:
			bet = new Bet(money + HandChecker.ROYAL_FLUSH * BET_INCREMENT,
					Bet.RAISE);
			break;
		}
		return bet;
	}

}
